from zope.interface import implements
import os, sys
import shutil
import zipfile
from datetime import date

APPLICATION_INSTALL_DIR = os.environ.get('SIMPLEWATCHER_INSTALL')
if not APPLICATION_INSTALL_DIR:
    raise EnvironmentError("must set environment variable SIMPLEWATCHER_INSTALL")
sys.path.append('%s/lib' % APPLICATION_INSTALL_DIR)

from watcher import WatcherObject
from watcher.action import RunBehavior
from watcher.utils import systemCommand
from watcher.exceptions import WatcherActionError

def debug(workItem, data, actionType):
    debug = data.get('debug')
    if debug and debug.lower() == 'y':
        print "DEBUG: action type is %s" % actionType
        print "DEBUG: workItem is %s" % workItem
        print "DEBUG: debugging data is %s" % data


class TemplateBehavior(RunBehavior):
    """template run behavior"""
    

class SystemCommand(RunBehavior):
    """execute a system command"""
    
    def __call__(self, workItem, data):
        """args can be string or list, either way"""
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "system_command")
        # start real handling
        cmd = data['cmd']
        args = data.get('args')
        if isinstance(args, list):
            args = ' '.join(args)
        cmd += u" " + unicode(args)
        try:
            (o, e) = systemCommand(cmd)
        except:
            raise WatcherActionError()
        return (o, e)



class FileCopy(RunBehavior):
    """copy a file"""
    
    def __call__(self, workItem, data):
        """copy a work item from one dir to another"""
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "file_copy")
        # start real handling
        toDir = data['toDir']
        newName = data.get('newName')
        fname = os.path.basename(workItem)
        if newName is None:
            newName = fname
        fromDir = os.path.dirname(workItem)
        newfname = os.path.join(toDir, newName)
        try:
            shutil.copyfile(workItem, newfname)
        except IOError:
            raise WatcherActionError("File %s was not able to be copied from %s to %s" % (fname, fromDir, toDir))


class FileMove(RunBehavior):
    """move a file"""
    
    def __call__(self, workItem, data):
        """move a work item from one dir to another"""
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "file_move")
        # start real handling
        toDir = data['toDir']
        newName = data.get('newName')
        fname = os.path.basename(workItem)
        if newName is None:
            newName = fname
        fromDir = os.path.dirname(workItem)
        newfname = os.path.join(toDir, newName)
        try:
            shutil.move(workItem, newfname)
        except IOError:
            raise WatcherActionError("File %s was not able to be moved from %s to %s" % (fname, fromDir, toDir))
        return newfname


class PrependLineData(RunBehavior):
    """prepend some kind of data to a work item"""
    
    def __call__(self, workItem, data):
        """make data and workitem into lists
           push data on the top
           return it back rejoined
        """
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "prepend_line_data")
        # start real handling
        raw_data = data['raw_data']
        f = open(workItem)
        data = f.readlines()
        f.close()
        d = raw_data.split(os.linesep)
        d.reverse()
        for val in d:
            data.insert(0, str(val) + os.linesep)
        f = open(workItem, 'w')
        f.writelines(data)
        f.close()


class PostpendLineData(RunBehavior):
    """postpend some kind of data to a work item"""
    
    def __call__(self, workItem, data):
        """make data and workitem into lists
           extend workitem by data
           return it back rejoined
        """
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "postpend_line_data")
        # start real handling
        raw_data = data['raw_data']
        f = open(workItem)
        f.close()
        data = f.readlines()
        d = raw_data.split(os.linesep)
        for val in d:
            data.append(str(val) + os.linesep)
        f = open(workItem, 'w')
        f.writelines(data)
        f.close()
        
        


class CreateLineNumbers(RunBehavior):
    """create line numbers at a particular interval"""
    
    def __call__(self, workItem, data):
        """create line numbers for a set of data"""
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "create_line_numbers")
        # start real handling
        startRange = int(data.get('startRange', 0))
        endRange = int(data['endRange'])
        f = open(workItem)
        data = f.readlines()
        f.close()
        r = startRange
        newWi = []
        for line in data:
            if r == endRange:
                r = startRange
            newWi.append("%04d" % r + line)
            r += 1
        newData = ''.join(newWi)
        f = open(workItem, 'w')
        f.write(newData)
        f.close()


class Compress(RunBehavior):
    """compress a file with zlib"""
    
    def __call__(self, workItem, data):
        # generic "if we're set to debug, then print out our data" debug action
        debug(workItem, data, "compress")
        # start real handling
        origFile = data.get('origFile', workItem)
        zipType = data.get("zipType", 'plain')
        toFile = data.get('toFile', os.path.basename(workItem))
        origAction = data.get('origAction')
        fromDir = os.path.dirname(origFile)
        if zipType.lower() == "date":
            # if it's date, then we need a format
            # and zipFile is just the postpend
            fmt = str(data.get('dateFormat'))
            filename = "%s%s" % (toFile, date.today().strftime(fmt))
            filename = os.path.join(fromDir, filename)
        elif zipType.lower() == 'plain':
            filename = os.path.join(fromDir, toFile)
        try:
            indata = open(origFile, 'rb').read()
            fh = zipfile.ZipFile("%s.zip"%filename, 'w', zipfile.ZIP_DEFLATED)
            fh.writestr(toFile, indata)
            fh.close()
        except:
            if data.get('onFailure', 'die').lower() == 'ignore':
                pass
            else:
                raise
        if origAction.lower() == 'remove':
            try:
                os.unlink(origFile)
            except:
                # we don't want to die just because we couldn't get rid of the file
                pass

